#include "Connector.h"
#include <MSWSock.h>
#include "Service.h"

Connector::Connector()
{
	m_Socket = INVALID_SOCKET;
	m_pHandler = 0;
	m_pCompletePort = 0;
}

Connector::~Connector()
{
	if ( m_Socket != INVALID_SOCKET )
	{
		closesocket(m_Socket);
		m_Socket = INVALID_SOCKET;
	}

	if ( m_pHandler )
	{
		delete m_pHandler;
		m_pHandler = 0;
	}

}

void Connector::connect(const char* addr,uint16 port,IConnectHandler* pHandler,ICompletePort* icp)
{
	if ( m_Socket != INVALID_SOCKET ) return ;
	if ( pHandler == 0 ) return ;
	if ( icp == 0 ) return ;

	m_pHandler = pHandler;
	m_pCompletePort = icp;

	sockaddr_in in_addr;
	in_addr.sin_family = AF_INET;
	in_addr.sin_port = htons(port);
	in_addr.sin_addr.s_addr = inet_addr(addr);

	remote_address_ = in_addr;
	m_Socket =::socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
	m_pCompletePort->Active((HANDLE)m_Socket,(void*)this);

	local_address_.sin_family = AF_INET;
	local_address_.sin_port = 0;
	local_address_.sin_addr.s_addr = INADDR_ANY;
	::bind(m_Socket,(sockaddr*)&local_address_,sizeof(sockaddr));

	LPFN_CONNECTEX ConnectEx = 0;
	GUID idConnectEx = WSAID_CONNECTEX;
	DWORD len = sizeof(GUID);
	DWORD ret;
	::WSAIoctl(m_Socket,SIO_GET_EXTENSION_FUNCTION_POINTER,&idConnectEx,len,&ConnectEx,4,&ret,0,0);

	m_Olap.reset(0);
	m_Olap.poster = this;
	m_Olap.OnComplete.OnComplete = ConnectorCallback::OnConnect;
	ConnectEx(m_Socket,(sockaddr*)&in_addr,sizeof(sockaddr),0,0,&ret,&m_Olap);
}

void Connector::connect_complete()
{
	if(m_Olap.success==FALSE)
	{
		closesocket(m_Socket);

		m_Socket = INVALID_SOCKET;
		remote_address_.sin_addr.s_addr = INADDR_NONE;		

		m_pHandler->Fail();
	}
	else
	{
		Service* svc = MyNew Service(m_Socket);

		m_Socket = INVALID_SOCKET;
		remote_address_.sin_addr.s_addr = INADDR_NONE;
		
		m_pHandler->Success(svc);
	}

	delete this;
}

void Connector::ConnectorCallback::OnConnect(olap * ptrOlap, void *, void *)
{
	Connector* c = (Connector*)ptrOlap->poster;
	assert ( CRuntime::IsValidHeapPoint(c) );
	c->connect_complete();
}